﻿using System;
using System.IO;
using System.Net.NetworkInformation;
using System.Text;
using Microsoft.Live;
using Notes.Model;
using System.Windows;
using System.Xml.Linq;
using System.Linq;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using Notes.Helpers;

namespace Notes.ViewModels
{
    public class SyncViewModel
    {
		public bool isSyncStarted { get; private set; }
        private SkyDriveHelper SkyDrive = null;

        private ObservableCollection<Category> LocalCategories;
        private ObservableCollection<Note> LocalNotes;
        private ObservableCollection<Photo> LocalPhotos;

        private ObservableCollection<Category> RemoteCategories;
        private ObservableCollection<Note> RemoteNotes;
        private ObservableCollection<Photo> RemotePhotos;

        private ObservableCollection<Category> MergedCategories;
        private ObservableCollection<Note> MergedNotes;
        private ObservableCollection<Photo> MergedPhotos;

        public SyncViewModel()
        {
            SkyDriveHelper SkyDrive = new SkyDriveHelper(App.SkyDriveClient);

            this.LocalCategories = App.MainViewModel.Categories;
            this.LocalNotes = App.MainViewModel.Notes;
            this.LocalPhotos = App.MainViewModel.Photos;
        }

        #region XML

        private string xmlSet()
		{
            string tplXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<notes>\n<categories>\n{0}\n</categories>{1}\n<photos>{2}\n</photos>\n</notes>";
			string tplCategory = "\n<category>\n<id>{0}</id>\n<edited>{1}</edited>\n<color>{2}</color>\n<name>{3}</name>\n<deleted>{4}</deleted>\n</category>";
			string strCategories = "";
			string tplNote = "\n<note>\n<id>{0}</id>\n<edited>{1}</edited>\n<category_id>{2}</category_id>\n<title>{3}</title>\n<text>{4}</text>\n<deleted>{5}</deleted>\n</note>";
			string strNotes = "";
            string tplPhoto = "\n<photo>\n<id>{0}</id>\n<note_id>{1}</note_id>\n<edited>{2}</edited>\n<file>{3}</file><deleted></deleted>\n</photo>";
            string strPhotos = "";
            StringWriter strXml = new StringWriter();

			foreach (Category c in App.db.Categories)
			{
				StringWriter strCategory = new StringWriter();
				strCategory.Write(tplCategory, c.Id, c.Edited.ToLocalTime(), c.Color, c.Name, c.Deleted.ToString());
				strCategories += strCategory.ToString();
			}
			foreach (Note n in App.db.Notes)
			{
				StringWriter strNote = new StringWriter();
				strNote.Write(tplNote, n.Id, n.Edited.ToLocalTime(), n.CategoryId, n.Title, n.Text, n.Deleted.ToString());
				strNotes += strNote.ToString();
			}
            foreach (Photo p in App.db.Photos)
            {
                StringWriter strPhoto = new StringWriter();
                strPhoto.Write(tplPhoto, p.Id, p.NoteId, p.Edited, p.FileName);
                strPhotos += strPhoto.ToString();
            }

			strXml.Write(tplXml, strCategories, strNotes, strPhotos);
			return strXml.ToString();
		}

        private void notesCompare(ObservableCollection<Note> xmlRemote)
        {
            foreach (Note rn in xmlRemote)
            {
                var result = from n in App.db.Notes where (n.Id == rn.Id) select n;
                if (result.Count() > 0)
                {
                    Note ln = result.First();
                    if (ln.Edited < rn.Edited)
                    {
                        if (rn.Deleted)
                        {
                            App.db.Notes.DeleteOnSubmit(ln);
                        }
                        else
                        {
                            ln = rn;
                        }
                    }
                    else
                    {
                        if (ln.Deleted)
                        {
                            App.db.Notes.DeleteOnSubmit(ln);
                        }
                    }
                }
                else
                {
                    App.db.Notes.InsertOnSubmit(rn);
                }
                App.db.SubmitChanges();
            }

            //removeDeletedNotes();

        }

        private void photosCompare(ObservableCollection<Photo> xmlRemote)
        {
            foreach (Photo rp in xmlRemote)
            {
                var result = from p in App.db.Photos where (p.Id == rp.Id) select p;
                if (result.Count() > 0)
                {
                    Photo ln = result.First();
                    if (ln.Edited < rp.Edited)
                    {
                        if (rp.Deleted)
                        {
                            App.db.Photos.DeleteOnSubmit(ln);
                        }
                        else
                        {
                            ln = rp;
                        }
                    }
                    else
                    {
                        if (ln.Deleted)
                        {
                            App.db.Photos.DeleteOnSubmit(ln);
                        }
                    }
                }
                else
                {
                    App.db.Photos.InsertOnSubmit(rp);
                }
                App.db.SubmitChanges();
            }

            //removeDeletedPhotos();
        }

        private void removeDeletedNotes()
        {
            var result = from n in App.db.Notes where (n.Deleted) select n;
            foreach (Note n in result)
            {
                App.db.Notes.DeleteOnSubmit(n);
            }
            App.db.SubmitChanges();
        }

        private void removeDeletedPhotos()
        {
            var result = from p in App.db.Photos where (p.Deleted) select p;
            foreach (Photo p in result)
            {
                App.db.Photos.DeleteOnSubmit(p);
            }
            App.db.SubmitChanges();
        }

        public void SyncNotes()
        {
            Deployment.Current.Dispatcher.BeginInvoke(delegate
            {
                if (!isSyncStarted)
                {
                    SyncView.btnSync.IsEnabled = false;
                    isSyncStarted = true;
                    SyncView.loadingProgressBar.IsVisible = true;
                    SyncView.loadingProgressBar.Text = AppResources.strProgressStarted;
                    SyncView.SyncTextBlock.Text = "";

                    if (NetworkInterface.GetIsNetworkAvailable())
                    {
                        SkyDriveHelper SkyDrive = new SkyDriveHelper(App.SkyDriveClient);
                        if (App.settings.Contains("FolderId"))
                        {
                            xmlRead(App.settings["FileId"].ToString());
                        }
                        else
                        {
                            SkyDrive.GetFolderIdByName(App.settings["FolderId"].ToString());
                            SkyDrive.OnFolderIdFound += xmlRead;
                            xmlSearch(App.FileName);
                        }
                    }
                    else
                    {
                        SyncView.btnSync.IsEnabled = true;
                        SyncView.loadingProgressBar.IsVisible = false;
                        Messenger.ShowMessage("Error","No network available.");
                    }
                }
            });
        }

        public void SyncPhotos()
        {
            Deployment.Current.Dispatcher.BeginInvoke(delegate
            {
                if (!isSyncStarted)
                {
                    SyncView.btnSync.IsEnabled = false;
                    isSyncStarted = true;
                    SyncView.loadingProgressBar.IsVisible = true;
                    SyncView.loadingProgressBar.Text = AppResources.strProgressStarted;
                    SyncView.SyncTextBlock.Text = "";

                    if (NetworkInterface.GetIsNetworkAvailable())
                    {
                        if (App.settings.Contains("FileId"))
                        {
                            xmlRead(App.settings["FileId"].ToString());
                        }
                        else
                        {
                            xmlSearch(App.FileName);
                        }
                    }
                    else
                    {
                        SyncView.btnSync.IsEnabled = true;
                        SyncView.loadingProgressBar.IsVisible = false;
                        Messenger.ShowMessage("Error", "No network available.");
                    }
                }
            });
        }

        #endregion

        #region SkyDrive

        private void BackupRead(string FileName)
        {
            SkyDrive.GetFileIdByName(FileName);
            SkyDrive.OnFileIdFound += new Action<string>(SkyDrive_OnFileIdFound);
        }

        void SkyDrive_OnFileIdFound(string id)
        {
            SkyDrive.GetFileContentById(id);
            SkyDrive.OnFileContentReady += new Action<string>(SkyDrive_OnFileContentReady);
        }

        void SkyDrive_OnFileContentReady(string xml)
        {
            this.RemoteCategories = new ObservableCollection<Category>(SyncHelper.ParseCategories(xml));
            this.RemoteNotes = new ObservableCollection<Note>(SyncHelper.ParseNotes(xml));
            this.RemotePhotos = new ObservableCollection<Photo>(SyncHelper.ParsePhotos(xml));

            this.MergedCategories = SyncHelper.MergeCategories(this.LocalCategories,this.RemoteCategories);
            this.MergedNotes = SyncHelper.MergeNotes(this.LocalNotes, this.RemoteNotes);
            this.MergedPhotos = SyncHelper.MergePhotos(this.LocalPhotos, this.RemotePhotos);

            SyncHelper.UpdateLocalDatabase(this.MergedCategories, this.MergedNotes, this.MergedPhotos);

            SyncHelper.CombineBackupFile(this.MergedCategories, this.MergedNotes, this.MergedPhotos);
        }

        public void xmlSearch(string name)
        {
            string path = "me/skydrive/files";
            App.SkyDriveClient.GetAsync(path);
            App.SkyDriveClient.GetCompleted += new EventHandler<LiveOperationCompletedEventArgs>(SkyDriveClient_GetCompleted);
            SyncView.loadingProgressBar.Text = AppResources.strProgressSearchingBackup;
        }

        private void SkyDriveClient_GetCompleted(object sender, LiveOperationCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (e.Result != null)
                {
                    List<object> data = (List<object>)e.Result["data"];
                    foreach (IDictionary<string, object> file in data)
                    {
                        if ((string)file["name"] == "notes.txt")
                        {
                            App.settings["FileId"] = file["id"].ToString();
                            App.settings.Save();
                        }
                    }
                }

                if (App.settings.Contains("FileId"))
                {
                    xmlRead(App.settings["FileId"].ToString());
                }
                else
                {
                    string xml = xmlSet();
                    xmlWrite(xml, App.FileName);
                }
            }
            else
            {
                SyncView.SyncTextBlock.Text = "Error: " + e.Error.Message;
            }
        }

        private void xmlWrite(string xml, string file)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                SyncView.loadingProgressBar.Text = AppResources.strProgressSaving;
                byte[] buffer = Encoding.Unicode.GetBytes(xml);
                MemoryStream s = new MemoryStream(buffer);
                if (App.SkyDriveClient != null)
                {
                    string path = "me/skydrive";
                    App.SkyDriveClient.UploadAsync(path, file, true, s, null);
                    App.SkyDriveClient.UploadCompleted += new EventHandler<LiveOperationCompletedEventArgs>(SkyDriveClient_UploadCompleted);
                }
                else
                {
                    MessageBox.Show(AppResources.strMessageTextSkydriveLost, AppResources.strMessageTitleError, MessageBoxButton.OK);
                    SyncView.loadingProgressBar.IsVisible = false;
                    SyncView.btnSignin.IsEnabled = true;
                    SyncView.btnSync.IsEnabled = false;
                }
            });
        }

        private void SkyDriveClient_UploadCompleted(object sender, LiveOperationCompletedEventArgs e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                if (e.Error == null)
                {
                    var FileId = new Object();
                    e.Result.TryGetValue("id", out FileId).ToString();
                    App.settings["FileId"] = FileId.ToString();
                    App.settings.Save();
                    SyncView.loadingProgressBar.Text = SyncView.SyncTextBlock.Text = AppResources.strProgressFinished;
                }
                else
                {
                    SyncView.SyncTextBlock.Text = "Error: " + e.Error.ToString();
                }

                SyncView.btnSync.IsEnabled = true;
                SyncView.loadingProgressBar.IsVisible = false;
                SyncView.loadingProgressBar.Text = "";
                isSyncStarted = false;
            });
        }
                
        #endregion

    }
}
